package com.fs.controller;

import com.fs.model.*;
import com.fs.service.FATService;
import com.fs.service.FileService;
import com.fs.service.FolderService;
import com.fs.service.PathService;
import com.fs.util.FATFactory;
import com.fs.util.FATUtil;
import com.fs.view.FileView;
import com.fs.view.PropertyView;
import com.fs.view.RenameView;
import com.fs.view.delView;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainController {
    //组合hBox  vBox  flowPane
    @FXML
    private Pane manePane;
    //文件展示布局
    @FXML
    private FlowPane flowPane;
    //水平布局  展示搜索框 按钮等
    @FXML
    private HBox hBox;
    //垂直布局  展示树形目录
    @FXML
    private VBox vBox;

    @FXML
    private Button backButton;

    @FXML
    private Button diskDetail;

    @FXML
    private Button gotoButton;

    @FXML
    private Button searchButton;

    @FXML
    private TextField locField;//目录框,配合按钮点击事件

    @FXML
    private TextField searchField;//搜索框，,配合按钮点击事件
    //下面是鼠标右键事件，触发在文件布局框内
    //右键菜单栏  存放下面六个MenuItem
    private ContextMenu contextMenu=new ContextMenu(), contextMenu2=new ContextMenu();
    //空白处或者鼠标放在文件上  鼠标右键的菜单栏：新建文件、新建文件夹、文件更名、文件属性、文件删除、文件打开
    private MenuItem createFileItem, createFolderItem, openItem, renameItem, delItem, propItem;

    //显示文件树状试图控件,不用管
    private TreeView<String> treeView;
    FAT fat=FATFactory.getFATInstance();

    //下面几个个代表当前文件操作的数据信息
    private Label[] icons;//标签图标数组,代表文件夹或者目录，表示当前显示的文件或文件夹
    private List<DiskBlock> blockList;//存储当前显示文件的首个磁盘块，和icons一一对应
    private int index; //代表鼠标点击的位置
    private String nowFileName;//鼠标点击的文件或文件夹名字
    private String recentPath;//当前全路径名

    //rootNode c盘在树形图中的节点， recentNode 代表当前操作的磁盘目录
    private TreeItem<String> rootNode, recentNode;
    //路径——TreeItem<路径>>
    private Map<Path, TreeItem<String>> pathMap;




    public MainController(Stage primaryStage) throws IOException {
        FXMLLoader mainFxml = new FXMLLoader(getClass().getResource("main.fxml"));
        mainFxml.setController(this);
        Parent root = mainFxml.load();
        primaryStage.setScene(new Scene(root,1000,650));
        primaryStage.show();
    }
    //页面初始化函数，可以用来二次设置带@FXML文件的按钮等
    public void initialize(){
        System.out.println("初始化");
        //初始化右键菜单栏
        this.initContextMeun();
        pathMap=new HashMap<>();
        this.recentPath=FATUtil.DEFAULT_PATH_NAME;//初始化默认当前路径名为C:

        //初始化鼠标右键点击菜单
        flowPane.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) -> {//me是鼠标的位置，展示右键菜单栏。在空白处显示右键菜单栏。
            if (me.getButton() == MouseButton.SECONDARY && !contextMenu2.isShowing()) {
                contextMenu.show(flowPane, me.getScreenX(), me.getScreenY());
            }
            else {
                contextMenu.hide();
            }
        });
        //初始化鼠标右键功能
        this.menuItemSetOnActionInitialize();
        //初始化树形磁盘目录
        initTreeView();


    }
    private void initTreeView() {//初始话treeView;
        rootNode = new TreeItem<>("目录", new ImageView(FATUtil.DISK_IMG));
        rootNode.setExpanded(true);
        recentNode = rootNode;//最近节点就是根节点。
        pathMap.put(FATFactory.getFATInstance().getRootPath(), rootNode);//在路径图中加入节点；
        treeView = new TreeView<String>(rootNode);
        //绑定事件
        treeView.setCellFactory((TreeView<String> p) -> new TextFieldTreeCellImpl());
        treeView.setPrefWidth(200);
        vBox.getChildren().add(treeView);

        //testDataInit 测试数据加载
        testDataInit();

    }
    public void testDataInit(){
        //测试数据
        initTreeNode(fat.getRootPath(),this.rootNode);
        addIcon(fat.getBlockList(recentPath));
    }
    //递归加载树形目录
    private void initTreeNode(Path newPath, TreeItem<String> parentNode) {
        TreeItem<String> newNode = addNode(parentNode, newPath);
        if (newPath.getChildren().size()>0) {
            for (Path child : newPath.getChildren()) {
                initTreeNode(child, newNode);
            }
        }
    }
    private TreeItem<String> addNode(TreeItem<String> parentNode, Path newPath) {
        String pathName = newPath.getPathName();
        //切割路径名获取目录名显示在树形目录上
        String value = pathName.substring(pathName.lastIndexOf('\\') + 1);
        //映射TreeItem节点
        TreeItem<String> newNode = new TreeItem<String>(value, new ImageView(FATUtil.TREE_NODE_IMG));
        newNode.setExpanded(true);
        pathMap.put(newPath, newNode);
        parentNode.getChildren().add(newNode);
        return newNode;
    }


    /*
    当前文件显示切换
     */
    public void TreeItemAction(String pathName){
        PathService pathService=new PathService();
        // 鼠标点击事件  根据全路径路径名，更新当前显示的文件     blockList
        System.out.println("当前点击的磁盘目录:"+pathName);
        pathService.changePathPresent(pathName);
        //刷新并重新添加
        freshen();

    }
    FATService fatService=new FATService();
    //鼠标右键点击后产生的功能列表所对应的事件
    private void menuItemSetOnActionInitialize(){
        //createFileItem, createFolderItem, openItem, renameItem, delItem, propItem;
        createFileItem.setOnAction(ActionEvent -> {//创建文件。
            fatService.createFile(recentPath);
            freshen();//刷新显示的文件

        });

        createFolderItem.setOnAction(ActionEvent -> {//创建文件夹。
            fatService.createFolder(recentPath);
            freshen();//刷新显示的文件
            freshenTreeItem();//刷新磁盘目录显示
        });

        openItem.setOnAction(ActionEvent -> {//打开文件。
            onOpen();
        });

        renameItem.setOnAction(ActionEvent -> {//重命名文件或文件夹。
            fatService.rename(blockList,icons,pathMap,index);
        });

        delItem.setOnAction(ActionEvent -> {//删除文件或文件夹。
            DiskBlock thisBlock = blockList.get(index);
            if (fat.isOpenedFile(thisBlock)) {
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText(null);
                alert.setContentText("文件未关闭");
                alert.showAndWait();
            } else {
                new delView(thisBlock, fat, MainController.this);
                flowPane.getChildren().removeAll(flowPane.getChildren());
                addIcon(fat.getBlockList(recentPath));
            }
            freshenTreeItem();
        });

        propItem.setOnAction(ActionEvent -> {//文件详情。
            fatService.property(blockList,icons,pathMap,index);
        });
    }

    private void onOpen() {
        blockList=fat.getBlockList(recentPath);                 //修改处!!!!!!!!!!!!!!!!!!!
        DiskBlock thisBlock = blockList.get(index);
        for (DiskBlock block : blockList) {
            System.out.println(block);
        }
        if (thisBlock.getObject() instanceof File) {
            if (fat.getOpenedFiles().size() < 5) {
                if (fat.isOpenedFile(thisBlock)) {
                    Alert duplicate = new Alert(Alert.AlertType.ERROR, "文件已打开");
                    duplicate.showAndWait();
                } else {
                    fat.addOpenedFile(thisBlock);
                    new FileView((File) thisBlock.getObject(), fat, thisBlock);
                }
            } else {
                Alert exceed = new Alert(Alert.AlertType.ERROR, "文件打开已到上限");
                exceed.showAndWait();
            }
        } else {
            Folder thisFolder = (Folder) thisBlock.getObject();
            String newPath = thisFolder.getLocation() + "\\" + thisFolder.getFolderName();
            flowPane.getChildren().removeAll(flowPane.getChildren());
            addIcon(fat.getBlockList(newPath));
            locField.setText(newPath);
            recentPath = newPath;
            recentNode = pathMap.get(thisFolder.getPath());
        }
    }

    //鼠标双击点击文件或文件夹触发事件   使用全局的 index 、icons可以获取当前点击的文件或文件夹名字
    public void doubleClickAction(){
        //双击文件后发生的事件，如打开文件或者进入到文件目录
       System.out.println("双击文件");
       onOpen();
    }


    /*
        回退按钮点击事件   通过获取到的locField内容进行相关操作
     */
    @FXML
    void backButtonAction(ActionEvent event) {
        System.out.println("backButtonAction:"+locField.getText());

    }
    /*
    前进按钮点击事件  搭配
     */
    @FXML
    void gotoButtonAction(ActionEvent event) {
        System.out.println("gotoButtonAction");

    }

    @FXML
    void searchButtonAction(ActionEvent event) {
        System.out.println("searchButtonAction:"+this.searchField.getText());

    }
    @FXML
    void diskDetailAction(ActionEvent event) {
        System.out.println("diskDetailAction");
    }


    private void initContextMeun() {//右键菜单栏  写死，不用管，不影响其他任何地方

        createFileItem = new MenuItem("新建文件");
        createFolderItem = new MenuItem("新建文件夹");
        //空白处右键显示的
        openItem = new MenuItem("打开");
        delItem = new MenuItem("删除");
        renameItem = new MenuItem("重命名");
        propItem = new MenuItem("属性");
        //对着文件夹显示的。
        contextMenu = new ContextMenu(createFileItem, createFolderItem);
        contextMenu2 = new ContextMenu(openItem, delItem, renameItem, propItem);
    }

    //刷新当前要显示的文件和文件夹
    private void freshen(){
        //刷新当前显示的文件
        List<DiskBlock> presentBlockList = fat.getPresentBlockList();
        this.flowPane.getChildren().retainAll();
        this.addIcon(presentBlockList);

    }
    private void freshenTreeItem(){
        //刷新树形目录结构  这暂时写成这样，后续从Map中获取出来单独改发生变化的treeItem
        this.rootNode.getChildren().retainAll();
        initTreeNode(fat.getRootPath(),this.rootNode);
    }

    //已经写好，下面的不用动任何东西，后续其他地方也不会引用这里的
    public void addIcon(List<DiskBlock> bList) {//path起始是没有用的//获取该地址下所有文件和文件夹，然后加图标以及鼠标活动
        //加入新的文件先清空pane里面的
//        this.flowPane.getChildren().retainAll();
        blockList = bList;//在这里设置blocklist
        int n = bList.size();//磁盘块大小的list
        icons = new Label[n];//label类型//图标数组的每一个退保对应一个文件活这文件夹。
        for (int i = 0; i < n; i++) {
            if (bList.get(i).getObject() instanceof Folder) {
                icons[i] = new Label(((Folder) bList.get(i).getObject()).getFolderName(),
                        new ImageView(FATUtil.FOLDER_IMG));//贴文件夹图片,少了后面这半句new的话只有文字标签，没有图标。
            } else {
                icons[i] = new Label(((File) bList.get(i).getObject()).getFileName(), new ImageView(FATUtil.FILE_IMG));//贴文件的图标
            }
            icons[i].setContentDisplay(ContentDisplay.TOP);
            icons[i].setWrapText(true);
            flowPane.getChildren().add(icons[i]);//往流式布局中添加标签。
            icons[i].setOnMouseEntered(new EventHandler<MouseEvent>() {//鼠标点击响应时间。

                @Override
                public void handle(MouseEvent event) {
                    ((Label) event.getSource()).setStyle("-fx-background-color: #FF6EC7 ;");//霓虹粉色特效，
                }
            });//移动鼠标到上面的话，加入灰边特效

            icons[i].setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent event) {
                    ((Label) event.getSource()).setStyle("-fx-background-color: #ffffff;");//鼠标离开后
                }
            });
            icons[i].setOnMouseClicked(new EventHandler<MouseEvent>() {//鼠标双击覆盖原来的函数
                @Override
                public void handle(MouseEvent event) {//event是鼠标活动的变量
                    Label src = (Label) event.getSource();//鼠标标活动点击到的图标。
                    for (int j = 0; j < n; j++) {
                        if (src == icons[j]) {
                            index = j;//传给OPEN（）好让他知道打开哪一个。
                            nowFileName=src.getText();
                            System.out.println("当前选择文件:"+j+nowFileName);
                        }
                    }//图标数组中寻找该数组。
                    if (event.getButton() == MouseButton.SECONDARY && event.getClickCount() == 1) {//右键单机的话。
                        contextMenu2.show(src, event.getScreenX(), event.getScreenY());//展示右键第二菜单栏，位于src这个图标上。第一个变量是在哪触发，后面是在哪展示
                    } else if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2) {//双击
                        //TODO 完善鼠标双击后打开文件的操作
                        System.out.println("双击文件："+index);
                        doubleClickAction();

                    } else {
                        contextMenu2.hide();//其他鼠标活动，隐藏菜单
                    }
                }
            });
        }
    }
    public void removeNode(TreeItem<String> recentNode, Path remPath) {
        recentNode.getChildren().remove(pathMap.get(remPath));
        fat.removePath(remPath);
        pathMap.remove(remPath);
    }
    public TreeItem<String> getRecentNode() {
        return recentNode;
    }
    //磁盘点击事件绑定
    public final class TextFieldTreeCellImpl extends TreeCell<String> {//最终类设置treeview活动

        private TextField textField;

        public TextFieldTreeCellImpl() {

            this.setOnMouseClicked(new EventHandler<MouseEvent>() {//点击节点事件
                @Override
                public void handle(MouseEvent event) {
                    if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 1) {
                        if (getTreeItem() != null) {
                            String pathName = null;
                            for (Map.Entry<Path, TreeItem<String>> entry : pathMap.entrySet()) {//遍历图找到与只对应的路径，返回该treeitem对应的路径名。
                                if (getTreeItem() == entry.getValue()) {
                                    pathName = entry.getKey().getPathName();
                                    break;
                                }
                            }
                            //点击目录后触发的事件
                            recentPath = pathName;//当前点击的路径名
                            recentNode = getTreeItem();//设置到当前
                            locField.setText(recentPath);//目录框设置显示。
                            TreeItemAction(pathName);//具体更新数据
                        }
                    }
                }
            });
        }

        @Override
        public void startEdit() {
            super.startEdit();

            if (textField == null) {
                createTextField();
            }
            setText(null);
            setGraphic(textField);
            textField.selectAll();
        }

        @Override
        public void cancelEdit() {
            super.cancelEdit();
            setText((String) getItem());
            setGraphic(getTreeItem().getGraphic());
        }

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(getTreeItem().getGraphic());
                }
            }
        }

        private void createTextField() {
            textField = new TextField(getString());
            textField.setOnKeyReleased((KeyEvent t) -> {
                if (t.getCode() == KeyCode.ENTER) {
                    commitEdit(textField.getText());
                } else if (t.getCode() == KeyCode.ESCAPE) {
                    cancelEdit();
                }
            });

        }

        private String getString() {
            return getItem() == null ? "" : getItem().toString();
        }

    }

}
